package com.xiguaji.tiktok.task.user;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.xiguaji.boot.toolkit.ThreadPoolUtils;
import com.xiguaji.boot.toolkit.jdbc.JdbcTemplateHelper;
import com.xiguaji.tiktok.task.user.repository.DicAdsRepository;
import com.xiguaji.tiktok.task.user.repository.SysMenuRepository;
import com.xiguaji.tiktok.task.user.repository.SysMenuVisitRecordRepository;
import com.xiguaji.tiktok.task.user.repository.UserAdsStatisticsRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;

@Service
public class UserAdsStatisticsService {

    @Autowired
    UserAdsStatisticsRepository userAdsStatisticsRepository;

    @Autowired
    DicAdsRepository dicAdsRepository;

    @Autowired
    SysMenuRepository sysMenuRepository;

    @Autowired
    SysMenuVisitRecordRepository sysMenuVisitRecordRepository;

    /**
     * 菜单访问统计
     */
    public void menuVisitRecordSt(){
        //记录前一天时间
        DateTime dateTime = DateUtil.yesterday();
        int dateCode = Integer.parseInt(DateUtil.format(dateTime,"yyyyMMdd"));
        getMenu(0,dateCode);
    }

    /**
     * 用户渠道统计
     */
    public void userAdsSt(){
        Iterable<DicAds> ads = dicAdsRepository.findAll();
        List<UserAdsStatistics> lists = new ArrayList<>();
        //记录前一天时间
        DateTime dateTime = DateUtil.yesterday();
        int dateCode = Integer.parseInt(DateUtil.format(dateTime,"yyyyMMdd"));
        long beginOfDay = DateUtil.beginOfDay(dateTime).getTime()/1000;
        long endOfDay = DateUtil.endOfDay(dateTime).getTime()/1000;

        ads.forEach( s->{
            UserAdsStatistics userAdsStatistics = new UserAdsStatistics();
            userAdsStatistics.setAdsType(s.getId());
            userAdsStatistics.setDateCode(dateCode);
            userAdsStatistics.setDateTime(System.currentTimeMillis()/1000);
            lists.add(userAdsStatistics);
        });


        //活跃用户
        List<Count> activeUser= getActiveUser(dateCode);
        //注册用户
        List<Count> registerUser = getNewRegister(beginOfDay);
        //新增付费用户
        List<Count> newPayUser = getNewPayUser(beginOfDay);
        //首次付费
        List<Count> firstPayUser = getFirstPayUser(beginOfDay);
        //用户总数
        List<Count> totalUser = getTotalUser(endOfDay);
        //从末付过钱的用户
        List<Count> nonPayUser = getNonPayUser(endOfDay);
        // 过期的用户
        List<Count> expireTimeUser = getExpireTimeUser(endOfDay);

        List<Count> advancedUser = getUserForVersion(3,beginOfDay,endOfDay);

        //累积付费
        List<Count> payUser = payUser();

        List<Count> proUser = getUserForVersion(4,beginOfDay,endOfDay);

        lists.parallelStream().forEach(l->{
            for (Count count : activeUser) {
                if(l.getAdsType() == count.getId()){
                    l.setActiveUser(count.getCount());
                    break;
                }
            }

            for (Count count : registerUser) {
                if(l.getAdsType() == count.getId()){
                    l.setRegisterUser(count.getCount());
                    break;
                }
            }

            for (Count count : newPayUser) {
                if(l.getAdsType() == count.getId()){
                    l.setAddPay(count.getCount());
                    break;
                }
            }

            for (Count count : firstPayUser) {
                if(l.getAdsType() == count.getId()){
                    l.setFristPay(count.getCount());
                    break;
                }
            }

            for (Count count : totalUser) {
                if(l.getAdsType() == count.getId()){
                    l.setUserCount(count.getCount());
                    break;
                }
            }

            for (Count count : nonPayUser) {
                if(l.getAdsType() == count.getId()){
                    l.setFreeCount(l.getFreeCount() + count.getCount());
                    break;
                }
            }
            for (Count count : expireTimeUser) {
                if(l.getAdsType() == count.getId()){
                    l.setFreeCount(l.getFreeCount() + count.getCount());
                    break;
                }
            }
            for (Count count : advancedUser) {
                if(l.getAdsType() == count.getId()){
                    l.setAdvanceCount(count.getCount());
                    break;
                }
            }
            for (Count count : proUser) {
                if(l.getAdsType() == count.getId()){
                    l.setProCount(count.getCount());
                    break;
                }
            }
            for (Count count : payUser) {
                if(l.getAdsType() == count.getId()){
                    l.setHistoryPay(count.getCount());
                    break;
                }
            }
            userAdsStatisticsRepository.save(l);
        });

        // 记录昨天日期
        countUserByLogin(dateCode,DateUtil.offsetDay(dateTime,-1),1);
        // 记录三天前日期
        countUserByLogin(dateCode,DateUtil.offsetDay(dateTime,-3),2);
        // 记录七天前日期
        countUserByLogin(dateCode,DateUtil.offsetDay(dateTime,-7),3);

    }

    public void countUserByLogin(int dateCode,DateTime beforeTime,int flag){
        int beforeDateCode = Integer.parseInt(DateUtil.format(beforeTime,"yyyyMMdd"));
        List<UserAdsStatistics> userAdsStatistics = userAdsStatisticsRepository.findByDateCode(beforeDateCode);

        if(userAdsStatistics.size() < 1){
            return;
        }


        List<Count> userLoginCount = getActiveUser(DateUtil.beginOfDay(beforeTime).getTime()/1000,DateUtil.endOfDay(beforeTime).getTime()/1000,dateCode);

        for (UserAdsStatistics userAdsStatistic : userAdsStatistics) {
            for (Count count : userLoginCount) {
                if(userAdsStatistic.getAdsType() == count.getId()){
                    if(flag == 1){
                        userAdsStatistic.setTowDayLogin(count.getCount());
                    }else if (flag == 2){
                        userAdsStatistic.setThreeDayLogin(count.getCount());
                    }else if (flag == 3){
                        userAdsStatistic.setSevenDayLogin(count.getCount());
                    }
                    userAdsStatisticsRepository.save(userAdsStatistic);
                    break;
                }
            }
        }
    }


    public void getMenu(int parentId,int dateCode){
        List<SysMenu> menus = sysMenuRepository.findByParentIdOrderByIdAsc(parentId);

        if(menus.size() < 1){
            return;
        }
        ForkJoinPool forkJoinPool = ThreadPoolUtils.forkJoinPool(menus.size(),"");
        long start = System.currentTimeMillis();
        try {
            forkJoinPool.submit( ()-> menus.parallelStream().forEach(menu -> {
                if(menu.getLevel() > 1){
                    List<Count> list = getCallVisitByMenuId(menu.getId(),dateCode,dateCode);
                    SysMenuVisitRecord sysMenuVisitRecord = new SysMenuVisitRecord();
                    sysMenuVisitRecord.setTotalVisit(list.get(0).getCount());
                    sysMenuVisitRecord.setTotalVisitUser(list.get(1).getCount());
                    sysMenuVisitRecord.setNonLoginVisit(list.get(2).getCount());
                    sysMenuVisitRecord.setNonLoginVisitUser(list.get(3).getCount());
                    sysMenuVisitRecord.setLoginVisit(list.get(4).getCount());
                    sysMenuVisitRecord.setLoginVisitUser(list.get(5).getCount());
                    sysMenuVisitRecord.setFreeVersionVisit(list.get(6).getCount());
                    sysMenuVisitRecord.setFreeVersionVisitUser(list.get(7).getCount());
                    sysMenuVisitRecord.setAdvanceVersionVisit(list.get(8).getCount());
                    sysMenuVisitRecord.setAdvanceVersionVisitUser(list.get(9).getCount());
                    sysMenuVisitRecord.setProVersionVisit(list.get(10).getCount());
                    sysMenuVisitRecord.setProVersionVisitUser(list.get(11).getCount());
                    sysMenuVisitRecord.setMenuId(menu.getId());
                    sysMenuVisitRecord.setDateCode(dateCode);
                    sysMenuVisitRecord.setCreateDate(System.currentTimeMillis()/1000);
                    sysMenuVisitRecord.setMobileUser(getMobile(menu.getId(),dateCode));
                    sysMenuVisitRecordRepository.save(sysMenuVisitRecord);
                }
                getMenu(menu.getId(),dateCode);
            })).get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        System.out.println((System.currentTimeMillis() - start)/1000+"s");
    }





    /**
     * 活跃用户
     * @param dateCode
     * @return
     */
    public List<Count> getActiveUser(int dateCode) {
        String sql = "select count(*) count,a.id from (SELECT DISTINCT(r.user_id),da.id FROM `sys_user_visit_record` r left join ads_record ar on r.user_id = ar.uid left join dic_ads da on ar.ads_type = da.id where  r.menu_id in (9,10,11) and r.date_code=?) a group by a.id";
        return JdbcTemplateHelper.getJdbcTemplate().query(sql,new BeanPropertyRowMapper<>(Count.class),dateCode);
    }

    public List<Count> getActiveUser(long startTime,long endTime,Integer dateCode) {
        String sql = "select count(*) count,a.id from (SELECT DISTINCT(r.user_id),da.id FROM `sys_user_visit_record` r left join ads_record ar on r.user_id = ar.uid left join dic_ads da on ar.ads_type = da.id where  ar.create_time >?  and ar.create_time <? and r.menu_id in (9,10,11) and r.date_code=?) a group by a.id";
        return JdbcTemplateHelper.getJdbcTemplate().query(sql,new BeanPropertyRowMapper<>(Count.class),startTime,endTime,dateCode);
    }



    /**
     * 注册用户
     * @param dateTime
     * @return
     */
    public List<Count> getNewRegister(long dateTime) {
        String sql = "select count(*) count,da.id from ads_record ar left join dic_ads da on da.id = ar.ads_type where ar.create_time > ? group by da.id";
        return JdbcTemplateHelper.getJdbcTemplate().query(sql,new BeanPropertyRowMapper<>(Count.class),dateTime);
    }

    /**
     * 新增付费用户
     * @param dateTime
     * @return
     */
    public List<Count> getNewPayUser(long dateTime) {
        String sql="select count(*) count,a.id from (" +
                "select distinct(o.user_id),da.id from product_order o " +
                "left join ads_record ar on o.user_id = ar.uid " +
                "left join dic_ads da on ar.ads_type = da.id " +
                "where o.create_time > ? and o.status = 1" +
                ") a group by a.id";

        return JdbcTemplateHelper.getJdbcTemplate().query(sql,new BeanPropertyRowMapper<>(Count.class),dateTime);
    }

    /**
     * 累积用户付费
     * @return
     */
    public List<Count> payUser() {
        String sql="select count(*) count,id from (" +
                "select o.user_id,da.id from product_order o " +
                "left join ads_record ar on o.user_id = ar.uid " +
                "left join dic_ads da on ar.ads_type = da.id " +
                "where o.status = 1 group by o.user_id) b " +
                "group by id";

        return JdbcTemplateHelper.getJdbcTemplate().query(sql,new BeanPropertyRowMapper<>(Count.class));
    }

    /**
     * 首次付费
     * @param dateTime
     * @return
     */
    public List<Count> getFirstPayUser(long dateTime) {
        String sql="select count(*) count,a.id from (" +
                "select o.user_id,da.id,count(*) count " +
                "from product_order o " +
                "left join ads_record ar on o.user_id = ar.uid " +
                "left join dic_ads da on ar.ads_type = da.id " +
                "where o.create_time > ? and o.status = 1 group by o.user_id" +
                ") a where a.count = 1 group by a.id";

        return JdbcTemplateHelper.getJdbcTemplate().query(sql,new BeanPropertyRowMapper<>(Count.class),dateTime);
    }

    /**
     * 用户总数
     * @return
     */
    public List<Count> getTotalUser(long endTime) {
        String sql="select count(*) count,da.id from ads_record ar left join dic_ads da on da.id = ar.ads_type where ar.create_time <= ? group by da.id";
        return JdbcTemplateHelper.getJdbcTemplate().query(sql,new BeanPropertyRowMapper<>(Count.class),endTime);
    }

    /**
     * 从末付过钱的用户
     * @return
     */
    public List<Count> getNonPayUser(long endTime) {
        String sql = "select count(*) count,da.id from user u left join user_role r on u.id = r.user_id left join ads_record ar on ar.uid = u.id left join dic_ads da on da.id = ar.ads_type where r.id is null and ar.create_time <= ? group by da.id order by da.id asc";
        return JdbcTemplateHelper.getJdbcTemplate().query(sql,new BeanPropertyRowMapper<>(Count.class),endTime);
    }

    /**
     * 过期的用户
     * @return
     */
    public List<Count> getExpireTimeUser(long endSecond) {
        Date date = new Date(endSecond*1000);
        String sql = "select count(*) count,da.id from ads_record ar left join dic_ads da on da.id = ar.ads_type left join user_role u on u.user_id = ar.uid where u.expire_time < ? and ar.create_time <= ?  group by da.id";
        return JdbcTemplateHelper.getJdbcTemplate().query(sql,new BeanPropertyRowMapper<>(Count.class),date,endSecond);
    }

    /**
     * 未过期的用户
     * @return
     */
    public List<Count> getUserForVersion(int version,long beginSecond,long endSecond) {
        Date date = new Date(beginSecond*1000);
        String sql = "select count(*) count,da.id from ads_record ar left join dic_ads da on da.id = ar.ads_type left join user_role u on u.user_id = ar.uid where u.expire_time > ? and u.role_id = ? and ar.create_time <= ? group by da.id";
        return JdbcTemplateHelper.getJdbcTemplate().query(sql,new BeanPropertyRowMapper<>(Count.class),date,version,endSecond);
    }

    public List<Count> getCallVisitByMenuId(int menuId, int startDateCode, int endDateCode) {
        return JdbcTemplateHelper.getJdbcTemplate().query("CALL userVisitExRobot(?,?,?)",BeanPropertyRowMapper.newInstance(Count.class),menuId,startDateCode,endDateCode);
    }


    public int getMobile(int menuId,int dateCode){
        String sql = "SELECT IFNULL( count(*), 0 ) AS count " +
                "FROM " +
                " ( SELECT user_id FROM `sys_user_visit_record` WHERE menu_id = ? AND date_code = ?  AND mobile = 1 GROUP BY user_key ) b ";
        return JdbcTemplateHelper.getJdbcTemplate().queryForObject(sql,Integer.class,menuId,dateCode);
    }




}
